/**
 * File: TranslateFastqQualityScore.java
 * Created by: mhaimel
 * Created on: Jun 23, 2010
 * CVS:  $Id: TranslateFastqQualityScore.java 1.0 Jun 23, 2010 3:33:51 PM mhaimel Exp $
 */
package uk.ac.ebi.curtain.exec;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.ebi.curtain.utils.data.FileType;
import uk.ac.ebi.curtain.utils.data.ReadType;
import uk.ac.ebi.curtain.utils.file.EntryMapper;
import uk.ac.ebi.curtain.utils.file.EntryMapperBean;
import uk.ac.ebi.curtain.utils.file.FileInfo;
import uk.ac.ebi.curtain.utils.file.SequenceQualityType;
import uk.ac.ebi.curtain.utils.file.WriteUtil;
import uk.ac.ebi.curtain.utils.io.impl.FileIO;
import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException;
import uk.co.flamingpenguin.jewel.cli.CliFactory;
import uk.co.flamingpenguin.jewel.cli.Option;

/**
 * @author mhaimel
 *
 */
public class TranslateFastqQualityScore {
	
	private static interface TranslateFastqQualityScoreScope {
		
		@Option(shortName = "o", description="Output file(s). If two files provided (and input files are paired) " +
				"the output will be split between them.")
		public List<File> getOutputFiles();
		
		public boolean isOutputFiles();
		
		// defaultValue=new String[]{SequenceQualityType.Sanger.toString()}
		@Option(shortName = "x", defaultValue="Illumina",description="Quality score encoding: Sanger, Illumina")
		public SequenceQualityType getOutputEncoding();
		
		public boolean isOutputEncoding();
		
		@Option(shortName = "e", defaultValue="Sanger",description="Quality score encoding: Sanger, Illumina (1.3+)")
		public SequenceQualityType getInputEncoding();
		
		public boolean isInputEncoding();
		
		@Option(shortName="i",description="Input file(s) - if two files are provided, the Paired flag has to be set!!!")
		public List<File> getInputFiles();
		
		public boolean isInputFiles();
				
		@Option(helpRequest = true, description = "display helpfull menu", shortName = "h")
		boolean getHelp();		
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TranslateFastqQualityScoreScope param = null;
		try {
			param = CliFactory.parseArguments(TranslateFastqQualityScoreScope.class, args);
		} catch (ArgumentValidationException e1) {
			System.err.println(e1.getMessage());
			System.exit(1);
		}
		boolean isStdout = false;
		int inSize = param.getInputFiles().size();
		int outSize = 0;
		List<File> outList = new ArrayList<File>();
		if(param.isOutputFiles()){
			outList = new ArrayList<File>(param.getOutputFiles());
			outSize = outList.size();
		} else {
			isStdout = true;
		}
		if(inSize == 1 ){
			if(outSize > 1){
				throw new IllegalArgumentException("Input and output parameters don't match!!! for one input file only 0 or 1 output files allowed!!!");
			}
		} else {
			if((outSize != inSize) && !isStdout && !(outSize == 1)){
				throw new IllegalArgumentException("Input and output parameters don't match!!! Either 1 output file or the amount of out files match the input files!!!");
			}
		}
		final SequenceQualityType from = param.getInputEncoding();
		final SequenceQualityType to = param.getOutputEncoding();
		final AtomicReference<PrintWriter> out = new AtomicReference<PrintWriter>();
		List<File> inList = new ArrayList<File>(param.getInputFiles());
		int iCnt = 0;
		final WriteUtil writer = FileType.fastq.getWriter();

		try {
			while(iCnt < inList.size()){
				
				FileInfo infile = new FileInfo(inList.get(iCnt), FileType.fastq, ReadType.Short);
				if(isStdout){
					if(out.get() == null){
						out.set(new PrintWriter(System.out));
					}
				}else {
					int pos = iCnt;
					if(pos < outList.size()){
						if(out.get() != null){
							FileIO.closeQuietly(out.getAndSet(null));
						}
						out.set(new FileIO(outList.get(pos)).getPrintWriter());
					}
				}	
				FileType.fastq.getParser().parse(infile, new EntryMapper() {
					
					@Override
					public void mapEntry(EntryMapperBean bean) {
						bean.setQuality(
								to.fromQuality(
								from.toQuality(
										bean.getQuality())));
						writer.write(out.get(), bean);
					}
				});
				++iCnt;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}	finally{
			FileIO.closeQuietly(out.getAndSet(null));
		}		
	}
}
